package com.hmc.modules.sjfx.util;

import org.apache.commons.math3.distribution.NormalDistribution;
import org.apache.commons.math3.stat.descriptive.DescriptiveStatistics;

import java.util.ArrayList;
import java.util.List;

/**
 * Apache Commons Math 用于正态分布的工具类
 */
public class NormalDistributionUtil {
    /**
     * 计算样本中值的平均数。
     *
     * @param values 样本数据列表
     * @return 样本的平均数
     * @throws IllegalArgumentException 如果样本数据为null或空
     */
    public static double getMean(List<Double> values) {

        // 如果样本数据为null或空，则抛出异常
        if (values == null || values.isEmpty()) {
            throw new IllegalArgumentException("Sample data cannot be null or empty");
        }
        return calculateStatistics(values).getMean();
    }

    /**
     * 计算样本中值的方差（标准差的平方）。给定样本的平均数，可以避免重复计算。
     *
     * @param values 样本数据列表
     * @param mean   样本的平均数
     * @return 样本的方差
     * @throws IllegalArgumentException 如果样本数据为null或空
     */
    public static double getVariance(List<Double> values, double mean) {
        // 如果样本数据为null或空，则抛出异常
        if (values == null || values.isEmpty()) {
            throw new IllegalArgumentException("Sample data cannot be null or empty");
        }
        // 返回样本的方差
        return calculateStatistics(values).getVariance();
    }

    /**
     * 计算样本中值的标准差。
     */
    public static double getStandardDeviation(List<Double> values) {
        // 如果样本数据为null或空，则抛出异常
        if (values == null || values.isEmpty()) {
            throw new IllegalArgumentException("Sample data cannot be null or empty");
        }
        // 返回样本的标准差
        return calculateStatistics(values).getStandardDeviation();

    }

    /**
     * 为正态分布曲线生成数据点列表。
     *
     * @param mean    正态分布的平均数
     * @param sd      正态分布的标准差
     * @param min     曲线的最小x值
     * @param max     曲线的最大x值
     * @param points  曲线上的点数
     * @return 正态分布曲线的数据点列表
     * @throws IllegalArgumentException 如果点的数量不大于1，或最小值等于最大值
     */
    public static List<Double> generateNormalDistributionCurve(double mean, double sd, double min, double max, int points) {
        // 如果点的数量不大于1，或最小值等于最大值，则抛出异常
        if (points <= 1) {
            throw new IllegalArgumentException("Number of points must be greater than 1");
        }
        // 如果最小值等于最大值，则抛出异常
        if (min == max) {
            throw new IllegalArgumentException("Min and max values must not be equal");
        }
        // 创建ArrayList对象
        List<Double> curve = new ArrayList<>();
        // 创建NormalDistribution对象
        NormalDistribution normalDistribution = new NormalDistribution(mean, sd);
        double interval = (max - min) / (points - 1); // 计算x值间隔
        // 生成曲线上的点
        for (int i = 0; i < points; i++) {
            double x = min + interval * i; // 计算每个点的x值
            curve.add(normalDistribution.density(x)); // 添加对应的密度值
        }
        return curve;
    }

    /**
     * 为 values 生成正态分布曲线数据点列表。
     * @param values 样本数据列表
     * @return 正态分布曲线的数据点列表
     */
    public static List<Double> generateNormalDistributionCurve(List<Double> values) {
        // 如果样本数据为null或空，则抛出异常
        if (values == null || values.isEmpty()) {
            throw new IllegalArgumentException("Sample data cannot be null or empty");
        }
        // 计算样本的平均数
        double mean = getMean(values);
        // 计算样本的标准差
        double sd = getStandardDeviation(values);

        // 为正态分布曲线生成数据点列表
        List<Double> curve = new ArrayList<>();

        values.forEach(value -> {
            curve.add(getDensity(value, mean, sd));
        });
        return curve;
    }

    /**
     * 计算给定点在正态分布下的概率密度值。
     *
     * @param x       给定的点
     * @param mean    正态分布的平均数
     * @param sd      正态分布的标准差
     * @return 给定点在正态分布下的概率密度值
     */
    public static double getDensity(double x, double mean, double sd) {
        // 创建NormalDistribution对象
        NormalDistribution normalDistribution = new NormalDistribution(mean, sd);
        // 返回给定点的概率密度值
        return normalDistribution.density(x);
    }

    /**
     * 计算样本的基本统计量。
     *
     * @param values 样本数据列表
     * @return 包含样本统计量的DescriptiveStatistics对象
     */
    public static DescriptiveStatistics calculateStatistics(List<Double> values) {
        // 创建DescriptiveStatistics对象
        DescriptiveStatistics stats = new DescriptiveStatistics();
        for (double value : values) {
            stats.addValue(value);
        }
        return stats;
    }

    /**
     * 取最小值
     *
     * @param values 样本数据列表
     * @return 样本的最小值
     */
    public static double getMin(List<Double> values) {
        if (values == null || values.isEmpty()) {
            throw new IllegalArgumentException("Sample data cannot be null or empty");
        }
        return calculateStatistics(values).getMin();
    }

    /**
     * 取最大值
     *
     * @param values 样本数据列表
     * @return 样本的最大值
     */
    public static double getMax(List<Double> values) {
        if (values == null || values.isEmpty()) {
            throw new IllegalArgumentException("Sample data cannot be null or empty");
        }
        return calculateStatistics(values).getMax();
    }
}
